/******************************************************************
 *  MRRM's execution unit                                         *
 *                                                                *
 *  This file is part of the MRRM project                         *
 *  <http://mrrm.googlecode.com/>                                 *
 *                                                                *
 *  Author(s):                                                    *
 *    -  Yuan Pengfei <coolypf@opencores.org>                     *
 *                                                                *
 ******************************************************************
 *                                                                *
 *  Copyright (C) 2010 AUTHORS                                    *
 *                                                                *
 *  This source file may be used and distributed without          *
 *  restriction provided that this copyright statement is not     *
 *  removed from the file and that any derivative work contains   *
 *  the original copyright notice and the associated disclaimer.  *
 *                                                                *
 *  MRRM is free software: you can redistribute it and/or modify  *
 *  it under the terms of the GNU General Public License as       *
 *  published by the Free Software Foundation, either version 3   *
 *  of the License, or (at your option) any later version.        *
 *                                                                *
 *  MRRM is distributed in the hope that it will be useful, but   *
 *  WITHOUT ANY WARRANTY; without even the implied warranty of    *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  *
 *  GNU General Public License for more details.                  *
 *                                                                *
 *  You should have received a copy of the GNU General Public     *
 *  License along with MRRM. If not, see                          *
 *  <http://www.gnu.org/licenses/>.                               *
 *                                                                *
 ******************************************************************/

`include "global.v"

module mrrm_exe(
	// Clock and reset
	clk, rst,
	// EXE interface
	E_vala, E_valb, E_valc,
	E_itype, E_isubtype, E_ifun, E_snl,
	e_valx, e_valy, e_bch
	);

parameter ow = `OPERAND_WIDTH;

// Interfaces
// Clock and reset
input clk;
input rst;

// EXE interface
input [ow-1:0] E_vala;
input [ow-1:0] E_valb;
input [ow-1:0] E_valc;
input [2:0] E_itype;
input [1:0] E_isubtype;
input [3:0] E_ifun;
input E_snl;
output [ow-1:0] e_valx;
output [ow-1:0] e_valy;
output e_bch;

// Internal wires and regs
reg v;
reg c;
reg n;
reg z;
wire alu_v;
wire alu_c;
wire alu_n;
wire alu_z;
wire [ow-1:0] alu_a;
wire [ow-1:0] alu_b;
reg [2:0] alu_op;
reg e_bch;

// ALU instance
mrrm_alu alu(.op(alu_op), .a(alu_a), .b(alu_b), .x(e_valx), .y(e_valy),
					.v(alu_v), .c(alu_c), .z(alu_z), .n(alu_n));

// Flag register control
always @(posedge clk or `RST_EVENT rst)
	if(rst == `RST_VALUE) begin
		{v, c, z, n} <= 4'b0;
	end
	else if(((E_itype == `I_REG && !(E_isubtype == `S_TWO && E_ifun == `F_JUMP))
			|| E_itype == `I_IMM) && E_snl == 1'b1) begin
		{v, c, z, n} <= {alu_v, alu_c, alu_z, alu_n};
	end

// ALU operands
assign alu_a = E_vala;
assign alu_b = (E_itype[0] == 1'b1) ? E_valb
	: (E_valb << E_valc);

// ALU operation
always @(E_itype[2:1] or E_isubtype or E_ifun)
	if(E_itype[2:1] == 2'b00)
		case (E_ifun)
			`F_AND:        alu_op = (E_isubtype == `S_ONE) ? `ALU_AND : `ALU_MUL;
			`F_SUB,
			`F_CSUB:       alu_op = `ALU_SUB;
			`F_ADD:        alu_op = (E_isubtype == `S_ONE) ? `ALU_ADD : `ALU_MULSL;
			`F_CAND:       alu_op = `ALU_AND;
			`F_CADD:       alu_op = `ALU_ADD;
			`F_ORR:        alu_op = `ALU_OR;
			`F_MOV:        alu_op = `ALU_MOV;
			default:       alu_op = `ALU_UDF;
		endcase
	else if(E_itype[2:1] == 2'b01)
		alu_op = `ALU_ADD;
	else
		alu_op = `ALU_UDF;

// Branch test
always @(E_itype or E_ifun or v or c or z or n)
	if(E_itype == `I_BXX) case (E_ifun)
		`COND_EQ:      e_bch = z;
		`COND_NE:      e_bch = ~z;
		`COND_UGE:     e_bch = c;
		`COND_ULT:     e_bch = ~c;
		`COND_N:       e_bch = n;
		`COND_NN:      e_bch = ~n;
		`COND_OV:      e_bch = v;
		`COND_NV:      e_bch = ~v;
		`COND_UGT:     e_bch = c & ~z;
		`COND_ULE:     e_bch = ~c | z;
		`COND_SGE:     e_bch = ~ (n ^ v);
		`COND_SLT:     e_bch = n ^ v;
		`COND_SGT:     e_bch = ~(z | (n ^ v));
		`COND_SLE:     e_bch = z | (n ^ v);
		`COND_AL:      e_bch = 1'b1;
		default:       e_bch = 1'b0;
	endcase
	else begin
		e_bch = 1'b0;
	end

endmodule
